#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
每日定时调度脚本：每天下午4点执行完整的数据处理流程
流程：tdx_control.py -> archive_txt_files.py -> generate_blocks.py -> rgg_ana_lite.py

兼容系统：Windows / Linux / macOS
"""

import schedule
import time
import subprocess
import sys
import os
from pathlib import Path
from datetime import datetime

# 确保在Windows上正确处理编码
if sys.platform == 'win32':
    import io
    sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8')
    sys.stderr = io.TextIOWrapper(sys.stderr.buffer, encoding='utf-8')

class DailyScheduler:
    """每日定时任务调度器"""
    
    def __init__(self, work_dir=None):
        """
        初始化调度器
        
        Args:
            work_dir: 工作目录（默认为当前脚本目录）
        """
        if work_dir is None:
            work_dir = Path(__file__).parent
        else:
            work_dir = Path(work_dir)
        
        # 确保目录存在
        work_dir.mkdir(parents=True, exist_ok=True)
        
        self.work_dir = work_dir
        self.log_file = work_dir / 'scheduler.log'
        self.platform = sys.platform  # 记录操作系统
        
    def log(self, message):
        """打印并保存日志（跨平台兼容）"""
        timestamp = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
        log_message = f"[{timestamp}] {message}"
        
        # Windows控制台输出
        try:
            print(log_message)
        except UnicodeEncodeError:
            # 如果有编码问题，使用替代字符
            print(log_message.encode('utf-8', errors='replace').decode('utf-8'))
        
        # 写入日志文件
        try:
            with open(self.log_file, 'a', encoding='utf-8') as f:
                f.write(log_message + '\n')
        except Exception as e:
            print(f"日志写入失败: {str(e)}")
    
    def run_script(self, script_name, description):
        """
        执行Python脚本
        
        Args:
            script_name: 脚本文件名
            description: 脚本描述
            
        Returns:
            bool: 是否执行成功
        """
        script_path = self.work_dir / script_name
        
        if not script_path.exists():
            self.log(f"❌ {description} 失败: 文件不存在 {script_path}")
            return False
        
        try:
            self.log(f"⏳ 开始执行: {description}")
            
            # 特殊处理：tdx_control.py 需要GUI交互权限
            is_gui_script = 'tdx_control' in script_name
            
            # Windows和Unix的subprocess调用方式略有不同
            if sys.platform == 'win32':
                # Windows系统 - 明确指定UTF-8编码，避免GBK解码错误
                
                # GUI脚本需要特殊的进程创建标志
                if is_gui_script:
                    self.log(f"   检测到GUI脚本，使用增强权限模式...")
                    # CREATE_NEW_CONSOLE = 0x00000010 - 创建新控制台，使子进程有前台权限
                    # 使用 Popen 以便实时读取输出
                    process = subprocess.Popen(
                        [sys.executable, str(script_path)],
                        cwd=str(self.work_dir),
                        stdout=subprocess.PIPE,
                        stderr=subprocess.PIPE,
                        text=True,
                        encoding='utf-8',
                        errors='replace',
                        creationflags=0x00000010,  # CREATE_NEW_CONSOLE
                        bufsize=1,  # 行缓冲
                        universal_newlines=True
                    )
                    
                    # 实时读取并打印输出
                    stdout_lines = []
                    stderr_lines = []
                    
                    # 读取标准输出
                    while True:
                        line = process.stdout.readline()
                        if not line:
                            break
                        line = line.rstrip()
                        if line:
                            print(f"  | {line}")  # 打印到屏幕
                            self.log(f"  | {line}")  # 记录到日志
                            stdout_lines.append(line)
                    
                    # 等待进程结束
                    return_code = process.wait(timeout=3600)
                    
                    # 读取错误输出
                    stderr_output = process.stderr.read()
                    if stderr_output:
                        for line in stderr_output.splitlines():
                            if line.strip():
                                print(f"  [ERR] {line}")
                                self.log(f"  [ERR] {line}")
                                stderr_lines.append(line)
                    
                    # 构造 result 对象以兼容后续代码
                    class Result:
                        def __init__(self, returncode, stdout, stderr):
                            self.returncode = returncode
                            self.stdout = '\n'.join(stdout)
                            self.stderr = '\n'.join(stderr)
                    
                    result = Result(return_code, stdout_lines, stderr_lines)
                else:
                    result = subprocess.run(
                        [sys.executable, str(script_path)],
                        cwd=str(self.work_dir),
                        capture_output=True,
                        text=True,
                        encoding='utf-8',  # 明确指定UTF-8编码
                        errors='replace',  # 遇到无法解码的字符用替换字符代替
                        timeout=3600,  # 1小时超时
                        shell=False
                    )
            else:
                # Unix-like系统（Linux/macOS） - 也明确指定UTF-8编码
                result = subprocess.run(
                    [sys.executable, str(script_path)],
                    cwd=str(self.work_dir),
                    capture_output=True,
                    text=True,
                    encoding='utf-8',
                    errors='replace',
                    timeout=3600  # 1小时超时
                )
            
            if result.returncode == 0:
                self.log(f"✅ {description} 完成")
                # 对于非-GUI脚本，也显示输出
                if not is_gui_script and result.stdout:
                    # 打印输出到屏幕
                    for line in result.stdout.splitlines():
                        if line.strip():
                            print(f"  | {line}")
                return True
            else:
                self.log(f"❌ {description} 失败 (代码: {result.returncode})")
                if result.stderr:
                    # 打印错误到屏幕
                    for line in result.stderr.splitlines()[:10]:  # 最多10行
                        if line.strip():
                            print(f"  [ERR] {line}")
                            self.log(f"   错误: {line}")
                return False
                
        except subprocess.TimeoutExpired:
            self.log(f"❌ {description} 超时（超过1小时）")
            return False
        except Exception as e:
            self.log(f"❌ {description} 异常: {str(e)}")
            return False
    
    def daily_task(self):
        """执行每日的完整任务流程"""
        self.log("=" * 60)
        self.log("开始执行每日定时任务")
        self.log("=" * 60)
        
        # 步骤1: 执行tdx_control.py - 从通达信导出数据
        if not self.run_script('tdx_control.py', '【步骤1】通达信数据导出'):
            self.log("⚠ 通达信导出失败，但继续执行后续流程...")
        
        time.sleep(2)  # 等待2秒
        
        # 步骤2: 执行archive_txt_files.py - 归档txt文件
        if not self.run_script('archive_txt_files.py', '【步骤2】txt文件归档'):
            self.log("⚠ txt文件归档失败，但继续执行后续流程...")
        
        time.sleep(2)  # 等待2秒
        
        # 步骤3: 执行generate_blocks.py - 生成板块数据
        if not self.run_script('generate_blocks.py', '【步骤3】板块数据生成'):
            self.log("⚠ 板块数据生成失败，停止执行")
            return False
        
        time.sleep(2)  # 等待2秒
        
        # 步骤4: 执行rgg_ana_lite.py - RRG分析
        if not self.run_script('rgg_ana_lite.py', '【步骤4】RRG分析'):
            self.log("⚠ RRG分析失败")
            return False
        
        self.log("=" * 60)
        self.log("✅ 今日所有任务执行完成")
        self.log("=" * 60)
        return True
    
    def schedule_daily_4pm(self):
        """安排每天下午4点执行"""
        try:
            schedule.every().day.at("16:00").do(self.daily_task)
            self.log("✓ 已安排每天下午16:00执行任务")
        except Exception as e:
            self.log(f"❌ 调度设置失败: {str(e)}")
            raise
    
    def start(self):
        """启动调度器（阻塞式，跨平台兼容）"""
        self.log(f"调度器启动中... (运行平台: {self.platform})")
        self.schedule_daily_4pm()
        
        try:
            self.log("调度器已启动，等待任务触发...")
            self.log("按 Ctrl+C 可停止调度器")
            while True:
                schedule.run_pending()
                time.sleep(60)  # 每分钟检查一次
        except KeyboardInterrupt:
            self.log("调度器已停止（用户中断）")
        except Exception as e:
            self.log(f"调度器异常: {str(e)}")
    
    def run_once(self):
        """立即执行一次任务（用于测试）"""
        self.log("执行一次性任务（测试模式）...")
        return self.daily_task()


def main():
    """主函数"""
    import argparse
    
    # Windows CMD/PowerShell可能需要额外的编码处理
    if sys.platform == 'win32':
        os.chdir(os.path.dirname(os.path.abspath(__file__)) or '.')
    
    parser = argparse.ArgumentParser(description='每日定时调度任务执行器')
    parser.add_argument(
        '--mode',
        choices=['start', 'test'],
        default='start',
        help='运行模式：start-启动调度器，test-执行一次'
    )
    parser.add_argument(
        '--work-dir',
        default=None,
        help='工作目录（默认为脚本所在目录）'
    )
    
    args = parser.parse_args()
    
    scheduler = DailyScheduler(work_dir=args.work_dir)
    
    if args.mode == 'test':
        # 测试模式：执行一次
        success = scheduler.run_once()
        sys.exit(0 if success else 1)
    else:
        # 正常模式：启动调度器
        scheduler.start()


if __name__ == '__main__':
    # 检查依赖包
    try:
        import schedule
    except ImportError:
        print("❌ 缺少schedule包，请执行: pip install schedule")
        print("   Windows用户请使用: python -m pip install schedule")
        sys.exit(1)
    
    # Windows任务计划程序提示
    if sys.platform == 'win32' and len(sys.argv) == 1:
        print("\n【Windows用户提示】")
        print("如要在Windows系统定时任务中运行，请参考 SCHEDULER_README.md")
        print("或使用菜单界面：python scheduler_quick_start.py\n")
    
    main()
